﻿using Mina.Core.Future;
using Mina.Core.Session;
using Mina.Transport.Socket;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace HttpPerfLoad
{
    class Pair
    {
        ConnectionManager connMgr;
        List<Pair> sessions;
        public Pair(List<Pair> sessions, ConnectionManager connMgr, AsyncSocketConnector connector, string host, int port)
        {
            this.sessions = sessions;
            this.connMgr = connMgr;
            this.connector = connector;
            this.host = host;
            this.port = port;
        }
        public bool ConnectInBackground(int index)
        {
            return ThreadPool.QueueUserWorkItem(ConnectThread, index);
        }
        string host;
        int port;
        public IConnectFuture cf;
        public AsyncSocketConnector connector;

        public IoSession Session { get; internal set; }
        internal bool SessionBroken { get { return _broken; } set { _broken = value; } }
        private bool _broken;
        internal bool connectProcessed;
        static bool firstConnectionOk;
        static bool firstConnectionFailed;
        void ConnectThread(object state)
        {
            var index = (int)state;
            while (index != 0 && !firstConnectionOk)
            {
                if (this.connMgr.stopRequested || firstConnectionFailed)
                {
                    connectProcessed = true;
                    this.connMgr.OnConnectionProgress(new ProgressInfo { current = index + 1, total = connMgr.numConnections, success = false });
                    return;
                }
                Thread.Sleep(100);
            }
            try
            {
                if (!this.connMgr.stopRequested)
                {
                    // Start communication.
                    IConnectFuture cf = connector.Connect(new IPEndPoint(IPAddress.Parse(host), port));
                    // Wait for the connection attempt to be finished.
                    cf.Await();
                    this.cf = cf;
                    this.Session = cf.Session;
                    if (index == 0)
                        firstConnectionOk = true;
                    lock (this.sessions)
                    {
                        this.Session.SetAttribute("pair", this);
                        this.sessions.Add(this);
                    }
                }
            }
            catch (Exception ex)
            {
                if (index == 0)
                {
                    firstConnectionFailed = true;
                }
                this.connMgr.OnConnectError(ex.Message, index);
                _broken = true;
            }
            finally
            {
                connectProcessed = true;
                this.connMgr.OnConnectionProgress(new ProgressInfo { current = index + 1, total = connMgr.numConnections, success = !_broken });
            }
        }
    }
}
